/*!
 * @file uniform.h
 * @ingroup MathUtil
 *
 * 
 *
 *
 */



#ifndef _QT_UNIFORM_H_
#define _QT_UNIFORM_H_

#include <cstdlib>
#include <cmath>
#include <cassert>

#include <boost/random.hpp>

#include "mathutil.h"
#include "randomutil.h"

namespace qt {

namespace random {



/*!
* This class provides access to standard functions
* associated with the standard uniform (0,1) distribution.
*/
class StdUniform {

public:
    /*!
     * Cumulative distribution.
     *
     * @param x is a real number
     * @returns Prob(X<x) where X is distributied U(0,1).
     *
     * History:
     *
     */
    static double cdf(double x) {
        return std::min(std::max(x,0.0),1.0);
    }

    /*!
     * Inverse of the cumulative distribution function.
     *
     * @param u a real number strictly between 0.0 and 1.0
     * @returns x the largest number such that P(X<x) < u.
     *
     * History:
     *
     */
    static double invCdf(double u) {
        return u;
    }


    /*!
     * The density function of the  distribution with respect to dx.
     *
     * @param x a real number
     * @returns Prob( x-dx < X < x+dx )/dx
     *
     * History:
     *
     */
    static double pdf(double x) {
        return ( x > 0.0 && x < 1.0 ? 1.0 : 0.0 );
    }

    /*!
     * This class defines some typedefs so that users
     * don't have to type long conpositions of templates.
     */

    template <typename GeneratorType>
    class GeneratorWrapper {

    public:

        typedef DistributionGenerator<GeneratorType,
                StdUniform> Generator;

        typedef WrappedGenerator
        < GeneratorType,
        DistributionGenerator<GeneratorType, StdUniform> >
        BoundGenerator;


    };


    /*! The default generator type */
    typedef
    GeneratorWrapper<qt::random::DefaultGeneratorType>::Generator
    DefaultGenerator;

    /*! The default type of generator that takes ownership of the
     * underlying generator.
     */
    typedef
    GeneratorWrapper<qt::random::DefaultGeneratorType>::BoundGenerator
    DefaultBoundGenerator;

    /*! Returns an instance of a default generator
     * associated with the global insance of a base generator.
     */
    static DefaultGenerator getDefaultGenerator() {
        DefaultGeneratorType & dgen =
            DefaultGeneratorType::getDefaultGenerator();
        StdUniform u;
        DefaultGenerator gen(dgen,u);
        return gen;
    }

    /*! Returns an instance of a generator associated
     * with the ugen argument.
     */
    template <typename GeneratorType>
    static typename GeneratorWrapper<GeneratorType>::Generator
    getGenerator(GeneratorType & ugen) {
        StdUniform u;
        typename GeneratorWrapper<GeneratorType>::Generator gen(ugen,u);
        return gen;
    }

    /*! Returns an instance of a generator that owns
     *  its own base generator.  Reseeding this generator
     *  will not affect other generators.
    */
    template<typename GeneratorType>
    static
    typename GeneratorWrapper<GeneratorType>::BoundGenerator
    getBoundGenerator(unsigned long seed = default_seed) {

        StdUniform u;

        typename GeneratorWrapper<GeneratorType>::BoundGenerator wgen(u);

        return wgen;
    }

};

class Uniform {

public:
    /*!
     * Cumulative distribution.
     *
     * @param x is a real number
     * @returns Prob(X<x) where X is distributied U(0,1).
     *
     * History:
     *
     */
    static double cdf(double x, double a, double b) {
        return std::min(std::max( (x-a)/(b-a) , 0.0), 1.0);
    }

    /*!
     * Inverse of the cumulative distribution function.
     *
     * @param u a real number strictly between 0.0 and 1.0
     * @returns x the largest number such that P(X<x) < u.
     *
     * History:
     *
     */
    static double invCdf(double u,double a, double b) {
        assert(u>=0 && u<=1);
        return (b-a)*u + a;
    }


    /*!
     * The density function of the  distribution with respect to dx.
     *
     * @param x a real number
     * @returns Prob( x-dx < X < x+dx )/dx
     *
     * History:
     *
     */
    static double pdf(double x,double a, double b) {
        return ( x > a && x < b ? 1.0/(b-a) : 0.0 );
    }

public:

    Uniform(double a=0.0, double b=1.0) : _a(a), _b(b) {}
    /*!
    * Cumulative distribution.
    *
    * @param x is a real number
    * @returns Prob(X<x) where X is distributied U(a,b).
    *
    * History:
    *
    */
    double cdf(double x) {
        return Uniform::cdf(x,_a,_b);
    }

    /*!
     * Inverse of the cumulative distribution function.
     *
     * @param u a real number strictly between 0.0 and 1.0
     * @returns x the largest number such that P(X<x) < u.
     *
     * History:
     *
     */
    double invCdf(double u) {
        return Uniform::invCdf(u,_a,_b);
    }


    /*!
     * The density function of the  distribution with respect to dx.
     *
     * @param x a real number
     * @returns Prob( x-dx < X < x+dx )/dx
     *
     * History:
     *
     */
    double pdf(double x) {
        return Uniform::pdf(x,_a,_b);
    }


    template <typename GeneratorType>
    class GeneratorWrapper {

    public:

        typedef DistributionGenerator<GeneratorType,
                Uniform> Generator;

        typedef WrappedGenerator
        < GeneratorType,
        DistributionGenerator<GeneratorType, Uniform > >
        BoundGenerator;


    };


    typedef
    GeneratorWrapper<qt::random::DefaultGeneratorType>::Generator
    DefaultGenerator;

    typedef
    GeneratorWrapper<qt::random::DefaultGeneratorType>::BoundGenerator
    DefaultBoundGenerator;

    static
    DefaultGenerator getDefaultGenerator(double a, double b) {
        DefaultGeneratorType & dgen =
            DefaultGeneratorType::getDefaultGenerator();
        Uniform u(a,b);
        DefaultGenerator gen(dgen,u);
        return gen;
    }

    template <typename GeneratorType>
    static
    typename GeneratorWrapper<GeneratorType>::Generator
    getGenerator(GeneratorType & ugen, double a, double b) {
        Uniform u(a,b);
        typename GeneratorWrapper<GeneratorType>::Generator gen(ugen,u);
        return gen;
    }

    /*! Returns an instance of a generator that owns
     *  its own base generator.  Reseeding this generator
     *  will not affect other generators.
    */
    template<typename GeneratorType>
    static
    typename GeneratorWrapper<GeneratorType>::BoundGenerator
    getBoundGenerator(double a, double b,
                      unsigned long seed = default_seed) {

        Uniform u(a,b);

        typename GeneratorWrapper<GeneratorType>::BoundGenerator wgen(u);

        return wgen;
    }



    double get_a() {
        return _a;
    }

    void set_a(double a) {
        _a = a;
    }

    double get_b() {
        return _b;
    }

    void set_b(double b) {
        _b = b;
    }

private:
    double _a;
    double _b;


};





}; // namespace qt::random

}; // namespace qt::


#endif
